package com.bw.tibjson;

import com.tibco.bw.store.RepoAgent;
import com.tibco.pe.model.TypeReference;
import com.tibco.pe.plugin.Activity;
import com.tibco.pe.plugin.ActivityException;
import com.tibco.pe.plugin.ConfigError;
import com.tibco.pe.plugin.ProcessContext;
import com.tibco.sax.EmptyEntityResolver;
import com.tibco.xml.data.primitive.ExpandedName;
import com.tibco.xml.datamodel.XiNode;
import com.tibco.xml.datamodel.XiParser;
import com.tibco.xml.datamodel.helpers.XiChild;
import com.tibco.xml.datamodel.parse.DefaultXiParser;
import com.tibco.xml.schema.SmElement;
import com.tibco.xml.schema.SmParticleTerm;
import com.tibco.xml.schema.SmSupport;
import com.tibco.xml.schema.parse.SmParseSupport;
import com.tibco.xml.xdata.bind.BindingRunner;
import java.io.IOException;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.XML;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 *
 * @author mabdelghany
 * @version 0.2
 */
public class JSONParseActivity extends Activity {

    private static final String SCHEMA = "<?xml version = \"1.0\" encoding = \"UTF-8\"?><xsd:schema xmlns:xsd = \"http://www.w3.org/2001/XMLSchema\" elementFormDefault = \"qualified\"><xsd:element name = \"jsonString\" type = \"xsd:string\"/></xsd:schema>";
    private SmParticleTerm outputTerm, inputTerm;
    private final EntityResolver ENTITY_RESOLVER = new EmptyEntityResolver();
    private final ThreadLocal THREAD_LOCAL = new ThreadLocal() {

        @Override
        protected Object initialValue() {
            return new DefaultXiParser();
        }
    };
    private final XiParser XI_PARSER = (XiParser) THREAD_LOCAL.get();

    /**
     * TODO:-xml only output(select schema)
     *      -
     */
    public JSONParseActivity() throws SAXException, IOException {
        StringReader stringReader = new StringReader(SCHEMA);
        try {
            inputTerm = SmSupport.getElement(SmParseSupport.parseSchema(new InputSource(stringReader)), "jsonString");
        } finally {
            stringReader.close();
        }
    }

    @Override
    public XiNode eval(ProcessContext pc, XiNode xinode) throws ActivityException {
        final String jsonString = xinode.getFirstChild().getStringValue();
        Logger.getLogger(JSONParseActivity.class.getName()).log(Level.INFO, jsonString);
        XI_PARSER.setParserHandlers(ENTITY_RESOLVER, null);
        XiNode xiNode2 = null;
        StringReader stringReader = null;
        try {
            stringReader = new StringReader(toXML(jsonString));
            xiNode2 = XI_PARSER.parse(new InputSource(stringReader));
            xiNode2 = BindingRunner.validate(xiNode2, this.procDef.getProcessScopeProvider(), getOutputTerm());
        } catch (Exception ex) {
            Logger.getLogger(JSONParseActivity.class.getName()).log(Level.SEVERE, null, ex);
            throw new ActivityException(ex.getLocalizedMessage());
        } finally {
            stringReader.close();
        }
        return xiNode2;
    }

    @Override
    public ConfigError[] getConfigErrors() {
        return super.getConfigErrors();
    }

    @Override
    public SmElement[] getErrorClasses() {
        return super.getErrorClasses();
    }

    @Override
    public SmParticleTerm getInputTerm() {
        return this.inputTerm;
    }

    @Override
    public SmParticleTerm getOutputTerm() {
        return this.outputTerm;
    }

    @Override
    public void setConfigParms(XiNode paramXiNode, RepoAgent paramRepoAgent) throws ActivityException {
        //xinode is the config part of the activity(xml), the output editor in this case.

        //expanded name must be the root node, in this case JSONParseActivityResource.getOutputSchemaEditorPropertyName().
        TypeReference localTypeReference = new TypeReference(XiChild.getChild(paramXiNode, ExpandedName.makeName("root")));

        try {
            setOutputTerm(localTypeReference.resolveTerm(paramRepoAgent, this.procDef.getNamespaceMapper(), this.procDef.getProcessScopeProvider(), this.procDef.getProcessScopeWsNsProvider()));
        } catch (Exception localException) {
//            setConfigError(ConfigErrorsHelper.createConfigError("BW-XML-100001", localException.toString()));
            localException.printStackTrace(System.err);
            Logger.getLogger(JSONParseActivity.class.getName()).log(Level.SEVERE, null, localException);
            throw new ActivityException(localException.getLocalizedMessage());
        }
    }

    @Override
    public boolean wantsOutputValidated() {
        return super.wantsOutputValidated();
    }

    @Override
    public void destroy() throws Exception {
//        throw new UnsupportedOperationException("Not supported yet.");
    }

    private void setOutputTerm(SmParticleTerm outputTerm) {
        this.outputTerm = outputTerm;
    }

    private String toXML(String jsonString) throws JSONException {
        String xmlString = "";
        final String TAG = this.outputTerm.getName() == null ? "root" : this.outputTerm.getName();
        try {
            JSONObject jsono = new JSONObject(jsonString);
            xmlString = XML.toString(jsono, TAG);
        } catch (JSONException ex) {
            Logger.getLogger(JSONParseActivity.class.getName()).log(Level.SEVERE, null, ex);
            throw ex;
        }
        return xmlString;
    }
}
